package objpool

import (
	"container/list"
	"log"
	"sync"
	"time"
)

type ObjPool struct {
	config PoolConfig //配置
	cond   *sync.Cond //条件锁用来等待
	total  int        //总个数
	objs   *list.List //对象存储
}

func NewObjPool(cfg PoolConfig) *ObjPool {
	return &ObjPool{
		config: cfg,
		cond: &sync.Cond{
			L: &sync.Mutex{},
		},
		total: 0,
		objs:  list.New(),
	}
}

//Lock 用来外部锁定,在外部锁定状态下不要操作pool,否则会造成死锁
func (o *ObjPool) Lock() {
	o.cond.L.Lock()
}

//Unlock 解除锁定状态
func (o *ObjPool) Unlock() {
	o.cond.L.Unlock()
}

func (o *ObjPool) wait() {
	o.cond.Wait()
}

func (o *ObjPool) add(obj interface{}) {
	o.objs.PushBack(obj)
}

func (o *ObjPool) pop() interface{} {
	if e := o.objs.Front(); e == nil {
		return nil
	}
	return o.objs.Remove(o.objs.Front())
}

//Get 获取对象,超过重试次数返回值为nil
func (o *ObjPool) Get() interface{} {
	o.Lock()
	defer o.Unlock()
	if o.objs.Len() > 0 {
		// log.Println("存在闲置obj")
		return o.pop()
	}
	//超过最大个数则等待释放
	for o.config.Max != 0 && o.config.Max <= o.total {
		// log.Println("总数已超过,等待")
		o.wait()
		if o.objs.Len() > 0 {
			// log.Println("总数已超过:成功获取")
			return o.pop()
		}
	}

	var value interface{}
	for i := 0; i < o.config.Retry; i++ {
		v, err := o.config.ObjFactory()
		if err != nil {
			log.Println("获取对象失败,准备重试", err)
			time.Sleep(o.config.RetryInterval)
			continue
		}
		value = v
		// log.Println("新建对象")
		break
	}
	if value != nil {
		o.total++
	}

	return value
}

//Put 放回
func (o *ObjPool) Put(v interface{}) {
	if v == nil {
		return
	}
	o.Lock()
	o.add(v)
	o.Unlock()
	o.cond.Signal()
}

//Drop 丢弃一个
func (o *ObjPool) Drop() {
	o.Lock()
	defer o.Unlock()
	o.total--
	if o.total < 0 {
		o.total = 0
	}
	o.cond.Signal()
}

//Reset 清除所有
func (o *ObjPool) Reset() {
	o.Lock()
	defer o.Unlock()
	o.total = 0
	o.objs.Init()
	o.cond.Broadcast()
}
